package com.credithc.eagleeye.plugins.druid;
import com.alibaba.druid.filter.AutoLoad;
import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
import com.alibaba.druid.proxy.jdbc.JdbcParameter;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import com.alibaba.druid.proxy.jdbc.ResultSetProxy;
import com.credithc.eagleeye.agent.factory.EagleEyeAgentFactory;
import com.credithc.eagleeye.constants.RpcTypeEnum;
import com.credithc.eagleeye.thread.EagleEyeThreadContext;
import com.credithc.eagleeye.thread.TraceInfo;
import com.credithc.eagleeye.util.FastJsonConvert;
import com.credithc.eagleeye.vo.RpcTraceInfoVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.SQLException;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
/**
 * 描 述: <br/>
 * 作 者: zhangjin<br/>
 * 创 建：2017年04月20日<br/>
 * 版 本：v1.0.0<br>
 * <p>
 * 历 史: (版本) 作者 时间 注释 <br/>
 */
@Deprecated
@AutoLoad(value = true)
public class EagleEyeDruidFilter extends FilterAdapter implements Filter {
    public static final Logger logger= LoggerFactory.getLogger(EagleEyeDruidFilter.class);
    private static final FastDateFormat ISO_DATETIME_TIME_ZONE_FORMAT_WITH_MILLIS = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ");
    @Override
    public ResultSetProxy preparedStatement_executeQuery(FilterChain chain, PreparedStatementProxy statement)
            throws SQLException {
        long startTime = System.currentTimeMillis();
        ResultSetProxy rs = super.preparedStatement_executeQuery(chain, statement);
        long endTime = System.currentTimeMillis();
        //发送到鹰眼
        send2EagleEye(chain.getDataSource(), showSql(statement), null, startTime, endTime);
        return rs;
    }
    @Override
    public int preparedStatement_executeUpdate(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
        DataSourceProxy dataSource = chain.getDataSource();
        long startTime = System.currentTimeMillis();
        int returnValue = super.preparedStatement_executeUpdate(chain, statement);
        long endTime = System.currentTimeMillis();
        //发送到鹰眼
        send2EagleEye(chain.getDataSource(), showSql(statement), returnValue, startTime, endTime);
        return returnValue;
    }
    private void send2EagleEye(DataSourceProxy dataSource, String sql, Object returnValue, long startTime, long endTime) {
        String jdbcUrl = StringUtils.substringBetween(dataSource.getUrl(), "jdbc:", "?");
        String databaseType = dataSource.getDbType();
        StackTraceElement stacks[] = Thread.currentThread().getStackTrace();
        String serviceName = "";
        String methodName = "";
        for(StackTraceElement stack : stacks) {
            String className = stack.getClassName();
            if (StringUtils.contains(className, "credithc") && !StringUtils.contains(className, "EagleEyeDruidFilter")) {
                serviceName = StringUtils.substringBefore(StringUtils.substringAfterLast(className, "."),"$");
                methodName = stack.getMethodName();
                break;
            }
        }
        long runTime = endTime - startTime;
        TraceInfo traceInfo = EagleEyeThreadContext.getTraceInfo();
        /*
        //每次都放入鹰眼
		if (traceInfo == null) {jdbcUrl = StringUtils.substringBetween(jdbcUrl, "jdbc:", "?");
			traceInfo = new TraceInfo();
			EagleEyeThreadContext.putTraceInfo(traceInfo);
		} else {
			traceInfo.addSequenceNo();
		}
		*/
        //当调用链不为空的时候，再放入鹰眼，防止无用的数据，比如定时任务访问数据库的信息
        if (traceInfo != null) {
            traceInfo.addSequenceNo();
            long beginTime = System.currentTimeMillis();
            Object resultObject = null;
            RpcTraceInfoVo rpcTraceInfoVo = new RpcTraceInfoVo();
            try {
                rpcTraceInfoVo.setRequestDateTime(ISO_DATETIME_TIME_ZONE_FORMAT_WITH_MILLIS.format(new Date(startTime)));
                rpcTraceInfoVo.setTraceId(traceInfo.getTraceId());
                rpcTraceInfoVo.setRpcId(traceInfo.getRpcId());
                rpcTraceInfoVo.setRpcType(RpcTypeEnum.DB.getRpcName());//
                rpcTraceInfoVo.setServiceCategory("druid");
                rpcTraceInfoVo.setServiceName(serviceName);
                rpcTraceInfoVo.setMethodName(methodName);
                rpcTraceInfoVo.setRequestJson(sql);
                rpcTraceInfoVo.setUserInfo(traceInfo.getUserInfo());
                rpcTraceInfoVo.setServerHost(jdbcUrl);
                rpcTraceInfoVo.setRunTime(runTime);
                rpcTraceInfoVo.setResult("OK");//OK
                rpcTraceInfoVo.setResponseJson(FastJsonConvert.convertObjectToJSON(returnValue));
            } catch (Exception ex) {
                rpcTraceInfoVo.setResult("ERROR");//ERROR
                ex.printStackTrace();
            } finally {
                try {
                    EagleEyeAgentFactory.getInstance().send2EagleEye(rpcTraceInfoVo);
                } catch (Exception ex) {
                    logger.error("druid send2EagleEye error:"+ex.getMessage());
                }
            }
        }
    }
    private static String showSql(PreparedStatementProxy statement) {
        String originalSql = statement.getSql();
        Map<Integer, JdbcParameter> parameters = statement.getParameters();
        String sql = originalSql.replaceAll("[\\s]+", " ");
        try {
            if (parameters != null && parameters.size() > 0) {
                for(int i = 0; i < parameters.size(); i++) {
                    JdbcParameter jdbcParameter = parameters.get(i);
                    sql = sql.replaceFirst("\\?", getParameterValue(jdbcParameter.getValue()));
                }
            }
        } catch (Exception ex) {
        }
        return sql;
    }
    private static String getParameterValue(Object obj) {
        String value = null;
        if (obj instanceof String) {
            value = "'" + obj.toString() + "'";
        } else if (obj instanceof Date) {
            DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.CHINA);
            value = "'" + formatter.format(new Date()) + "'";
        } else {
            if (obj != null) {
                value = obj.toString();
            } else {
                value = "null";
            }
        }
        return value;
    }
}
